package yartiss.engine.simulation.system.taskset;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;

import yartiss.engine.simulation.system.ITask;
import yartiss.engine.simulation.system.ITaskSet;
import yartiss.engine.simulation.system.schedulable.GraphTask;
import yartiss.engine.simulation.system.schedulable.SubTask;

/**
 * LaxityTaskSet is a class returns an ordered taskset according to the
 * least-laxity-first priority assignment technique
 * 
 * @author Manar Qamhieh
 * 
 */
public class LaxityGraphTaskSet implements ITaskSet {

	private List<ITask> graphs;
	private TreeSet<ITask> tasks;
	private long currentDate = 0;
	private int id;

	private final Comparator<ITask> comparator = new Comparator<ITask>() {
		@Override
		public int compare(ITask t1, ITask t2) {

			long laxity1 = t1.getLaxity() + ((SubTask) t1).getGraphLaxity() - currentDate;
			long laxity2 = t2.getLaxity() + ((SubTask) t2).getGraphLaxity() - currentDate;
			/*long laxity1 = t1.getLaxity() + ((SubTask) t1).getGraphLaxity();
			long laxity2 = t2.getLaxity() + ((SubTask) t2).getGraphLaxity();*/
			
			if(laxity1 == 0)return -1;
			if(laxity2 == 0)return 1;
			
			int cmp = (int) (laxity1 - laxity2);
			if (cmp == 0)
				cmp = (int) (t1.getPriority() - t2.getPriority());
			if (cmp == 0)
				return -1;
			return cmp;
		}
	};

	public LaxityGraphTaskSet() {
		this.graphs = new ArrayList<ITask>();
		this.tasks = new TreeSet<ITask>(comparator);
	}

	@Override
	public Iterator<ITask> iterator() {
		return tasks.iterator();
	}

	@Override
	public boolean addTask(ITask t) {
		GraphTask graph = (GraphTask) t;
		
		for (SubTask subtask : graph.getSubtasks()) {
			subtask.setGraphLaxity(t.getLaxity());
			tasks.add(subtask);
		}
		return graphs.add(t);
	}

	@Override
	public boolean addTasks(List<ITask> t) {
		for (ITask graph : t) {
			addTask(graph);
		}
		return graphs.addAll(t);
	}

	@Override
	public SortedSet<ITask> getActiveTasks(long date) {
		currentDate = date;
		boolean activated = true;
		SortedSet<ITask> activeTasks = new TreeSet<ITask>(comparator);
		
		for (ITask subtask : tasks) {
			if(!subtask.isActive()){
				continue;
				}
			activated = true;
			for (SubTask parent : ((SubTask) subtask).getParentTasks()) {
				if (parent.getRemainingCost() != 0) {
					activated = false;
					break;
				}
			}
			if (activated) {
				activeTasks.add(subtask);
			}
		}
		
	/*	for (ITask graph : graphs) {
			for (ITask subtask : ((GraphTask)graph).getSubtasks() ) {
				if(!subtask.isActive()) continue;
				activated = true;
				for (SubTask parent : ((SubTask)subtask).getParentTasks() ) {
					if(parent.getRemainingCost() != 0){
						activated = false;
						break;
					}
				}
				if(activated){
					activeTasks.add(subtask);
				}
			}
		}*/
		return activeTasks;
	}

	@Override
	public int getAllTasksCount() {
		return tasks.size();
	}

	@Override
	public SortedSet<ITask> getHeadSet(ITask task, boolean inclusive) {
		SortedSet<ITask> activeTasks = new TreeSet<ITask>(comparator);
		return activeTasks;
	}

	@Override
	public int getId() {
		return id;
	}

	@Override
	public int setId(int id) {
		return this.id = id;
	}

	@Override
	public ITask getOne() {
		return tasks.first();
	}
	
	@Override
	public ITaskSet cloneTaskSet() {
		PriorityTaskSet set = new PriorityTaskSet();
		for (ITask task : tasks) {
			set.addTask(task.cloneTask());
		}
		return set;
	}

}
